#include "tcp_connection.h"
#include "protocol/command.h"
#include <boost/bind.hpp>

TcpConnection::TcpConnection(io_service& io_server)
:socket_(io_server), strand_(io_server)
{
	boost::asio::socket_base::keep_alive option(true);
	socket_.set_option(option);
	tcp::no_delay noDelay(true);
	socket_.set_option(noDelay);
}

void TcpConnection::start()
{
	remote_addr_ = socket_.remote_endpoint().address().to_string();
	remote_port_ = socket_.remote_endpoint().port();

	TcpConnectionPtr ptr(shared_from_this());

	boost::asio::async_read(socket_, req_stream_, 
		boost::asio::transfer_at_least(1), strand_.wrap(
		std::bind(&TcpConnection::onMessage, shared_from_this(),
		boost::asio::placeholders::error,
		boost::asio::placeholders::bytes_transferred)));
}

void TcpConnection::onMessage(const boost::system::error_code& err,
	std::size_t bytes_transferred)
{
	if (!err)
	{
		handleMessage(req_stream_, )

	

		boost::asio::async_read(socket_, req_stream_,
			boost::asio::transfer_at_least(1), strand_.wrap(
			boost::bind(&TcpConnection::onMessage, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred)));
	}
	else
	{
		LOG4CPLUS_ERROR(Log, "response error: " << err.message());
	}
}

void TcpConnection::sendMessage(const std::string& message)
{
	{
		std::lock_guard<std::mutex> lock(mutex_); ostream os(&resp_stream_); os << message;
	}

	async_write(socket_, resp_stream_, strand_.wrap(
		boost::bind(&TcpConnection::onWriteFinish, shared_from_this(),
		boost::asio::placeholders::error,
		boost::asio::placeholders::bytes_transferred)));
}

void TcpConnection::onWriteFinish(const boost::system::error_code& err,
	std::size_t bytes_transferred)
{
	if (err)
	{
		LOG4CPLUS_ERROR(Log, "response error: " << err.message());
		disconnect();
	}
}

void TcpConnection::handleMessage(boost::asio::streambuf& sb, std::list<CommandPtr>& cmdList)
{
	std::string buff(sb.size(), '\0');
	std::istream is(&sb);
	is.read(&buff[0], sb.size());

	while(1)
	{
		CmdHead head;
		bool rst = decodeHead(buff, head);
		size_t length = kMsgHeadSize + head.bodyLen;
		if(!rst || buff.size() < length)
			break;

		std::string strCmd = CmdNameMap::name(head.cmdID);	
		google::protobuf::Message* message = createMessage(strCmd);
		if(NULL == message)
			break;

		std::string strBody = buff.substr(kMsgHeadSize, head.bodyLen);
		message->ParseFromString(strBody);

		CommandPtr pack(new Command);
		pack->head = head;
		pack->body.reset(message);
		//TODO process request message
		cmdList.push_back(pack);
		buff = buff.substr(length);
	}

	//将未解析完成的数据缓存回buff中
	if(!buff.empty())
	{
		std::ostream os(&sb);
		os << buff;
	}
}
